39 控制结构
39.1 引言程序控制流的理论基础
控制流(Control Flow)是程序设计的核心,决定了代码的执行顺序和逻辑分支。
理论背景:控制流图(Flowchart)
程序的三种基本控制结构(Bohm-Jacopini定理): 1. 顺序结构(Sequence): 语句按顺序依次执行 2. 选择结构(Selection): 根据条件选择执行路径(if-else) 3. 循环结构(Iteration): 重复执行某段代码(for/while)
数学基础:图论
控制流可以表示为有向图(Directed Graph): - 节点(Node): 表示程序语句 - 边(Edge): 表示控制流转移 - 路径(Path): 从入口到出口的执行路径
金融应用: - 交易策略: 条件判断买入/卖出 - 风险控制: 止损/止盈逻辑 - 批量处理: 遍历股票列表 - 迭代优化: 梯度下降法求解
39.2 if-else选择结构
39.2.1 条件表达式
理论背景:布尔逻辑与谓词逻辑
布尔(Boolean)代数由乔治·布尔于1854年创立,是现代计算机科学的基础。
三种基本运算: 1. 与(AND): A and B - 两者都真才真 2. 或(OR): A or B - 至少一个真就真 3. 非(NOT): not A - 真变假,假变真
短路求值(Short-circuit Evaluation):
A and B # 如果A为假,不计算B
A or B # 如果A为真,不计算B金融应用: 风险管理中的多层条件判断
# =============================================================================
# 题目:实现个人所得税累进税率计算系统
# =============================================================================
# 本任务演示如何使用if-elif-else结构实现累进税率计算
# 累进税率是现代税收制度的核心,体现"量能课税"原则
# 金融应用:薪酬管理、税务筹划、个人所得税申报
# ==================== 定义税收计算函数 ====================
def calculate_tax(salary):
"""
计算个人所得税(简化版)
原理:中国个人所得税采用7级超额累进税率
- 超额累进:只对超过该级的部分征税
- 速算扣除数:简化计算,避免分段计算
参数:
salary (float): 税前工资,单位:元
返回:
tuple: (tax, after_tax)
tax (float): 应缴税额
after_tax (float): 税后工资
"""
# ==================== 第一步:确定适用税率档次 ====================
# 使用if-elif-else结构匹配累进税率表
# 从低到高依次判断,一旦匹配就跳出(互斥关系)
# 第1级:月收入 <= 3000元
if salary <= 3000:
# 税率:0%(免税)
rate = 0 # 税率
deduction = 0 # 速算扣除数
# 第2级:3000 < 月收入 <= 12000
elif salary <= 12000:
# 税率:3%
rate = 0.03 # 适用税率
deduction = 0 # 速算扣除数(本级无需扣除)
# 第3级:12000 < 月收入 <= 25000
elif salary <= 25000:
# 税率:10%
rate = 0.10 # 适用税率
deduction = 210 # 速算扣除数(预扣除的税额)
# 第4级:25000 < 月收入 <= 35000
elif salary <= 35000:
# 税率:20%
rate = 0.20 # 适用税率
deduction = 1410 # 速算扣除数
# 第5级:35000 < 月收入 <= 55000
elif salary <= 55000:
# 税率:25%
rate = 0.25 # 适用税率
deduction = 2660 # 速算扣除数
# 第6级:55000 < 月收入 <= 80000
elif salary <= 80000:
# 税率:30%
rate = 0.30 # 适用税率
deduction = 4410 # 速算扣除数
# 第7级:月收入 > 80000
else:
# 税率:35%(最高档)
rate = 0.35 # 最高税率
deduction = 7160 # 速算扣除数
# ==================== 第二步:计算应纳税额 ====================
# 应纳税所得额 = 税前工资 - 起征点
taxable_income = salary - 5000 # 5000元是个税起征点(免征额)
# 应纳税额 = 应纳税所得额 × 税率 - 速算扣除数
tax = taxable_income * rate - deduction
# 使用max()确保税额不为负(最低为0元)
# 如果tax < 0,说明收入低于起征点,不需要纳税
tax = max(0, tax) # max(0, tax)返回两者中的较大值
# ==================== 第三步:计算税后工资 ====================
# 税后工资 = 税前工资 - 应纳税额
after_tax = salary - tax
# 返回税额和税后工资(元组形式)
return tax, after_tax
# ==================== 测试案例:不同收入水平的税收 ====================
# 创建测试工资列表:覆盖各个税率档次
salaries = [2500, 5000, 15000, 30000, 60000, 100000]
# 解读:从免税档到最高档,全面测试税率计算
# 打印表头
print('工资扣税计算:')
# 打印分隔线(60个减号)
print('-' * 60)
# ==================== 遍历每个工资案例进行计算 ====================
# for循环:依次对列表中的每个工资进行税收计算
for salary in salaries:
# 调用calculate_tax函数,返回税额和税后工资
tax, after_tax = calculate_tax(salary) # 元组解包
# 计算实际税负率(税额/税前工资)
# 三元表达式:如果salary > 0,计算税率,否则为0(避免除零错误)
tax_rate = tax / salary * 100 if salary > 0 else 0
# 格式化输出:使用f-string进行字符串格式化
# {salary:8.2f}:宽度8,保留2位小数,右对齐
# {tax:7.2f}:宽度7,保留2位小数
# {tax_rate:5.2f}:宽度5,保留2位小数
# {after_tax:8.2f}:宽度8,保留2位小数
print(f'税前工资: {salary:8.2f}元 | 税额: {tax:7.2f}元 | 税率: {tax_rate:5.2f}% | 税后: {after_tax:8.2f}元')代码深度解析:
- elif语句:
- “else if”的缩写
- 从上到下依次判断
- 一旦某个条件为真,执行对应分支后跳出
- 累进税率:
- 边际税率随收入增加
- 高收入部分适用更高税率
- 体现”量能课税”原则
- 起征点:
salary - 5000: 免税额- 低于5000元不纳税
- 保护低收入群体
39.2.2 复杂条件判断
补充说明:嵌套if与逻辑运算
当需要同时满足多个条件时,有两种写法:
写法1: 嵌套if
if condition1:
if condition2:
# 执行代码写法2: 逻辑运算
if condition1 and condition2:
# 执行代码选择建议: - 条件独立: 使用逻辑运算(and, or) - 条件相关: 使用嵌套if - 代码可读性优先
# =============================================================================
# 题目:实现基于技术分析的交易信号生成系统
# =============================================================================
# 本任务演示嵌套if结构和多条件判断在量化交易中的应用
# 交易信号生成是量化交易系统的核心模块,需要综合多个技术指标
# 金融应用:算法交易、量化策略、风险管理系统
# ==================== 定义交易信号生成函数 ====================
def generate_signal(price, ma20, ma60, volume, avg_volume, rsi):
"""
生成交易信号(基于技术指标的多条件判断)
策略逻辑:
1. 均线多头排列(MA20 > MA60)+ 价格突破 + 放量 + RSI未超买 → 买入
2. 均线空头排列(MA20 < MA60)+ 价格跌破 + 放量 + RSI未超卖 → 卖出
3. 其他情况 → 观望
参数:
price (float): 当前价格
ma20 (float): 20日移动平均线
ma60 (float): 60日移动平均线
volume (float): 当日成交量
avg_volume (float): 平均成交量
rsi (float): 相对强弱指标(范围0-100)
返回:
tuple: (signal, reason)
signal (str): 交易信号,'BUY'/'SELL'/'HOLD'
reason (str): 信号原因说明
"""
# ==================== 第一步:初始化信号状态 ====================
signal = 'HOLD' # 默认信号:观望(不交易)
reason = [] # 原因列表:用于记录信号生成的逻辑依据
# ==================== 第二步:判断市场趋势(第一层if) ====================
# 条件1:均线多头排列(短期均线 > 长期均线)
# 这是上升趋势的标志,表明近期价格走势强于长期趋势
if ma20 > ma60:
# 记录第一个判断依据:均线多头
reason.append('均线多头') # append()向列表添加元素
# ==================== 第三步:判断价格位置(第二层if - 嵌套) ====================
# 子条件:价格突破20日均线
# 这表明上涨动能强劲,可能是买入机会
if price > ma20:
# 记录第二个判断依据
reason.append('突破20日均线')
# ==================== 第四步:量价配合确认(第三层if - 深度嵌套) ====================
# 三重条件判断(使用and逻辑运算符):
# 条件A:成交量 > 平均成交量的1.2倍(放量确认)
# 条件B:RSI < 70(未超买,避免追高)
# and运算符:两个条件都为True时,整体为True
if volume > avg_volume * 1.2 and rsi < 70:
# 同时满足三个条件,发出买入信号
signal = 'BUY' # 修改信号为买入
reason.append('放量上涨') # 记录第三个判断依据
# ==================== 第五步:判断下跌趋势(elif分支) ====================
# 条件2:均线空头排列(短期均线 < 长期均线)
# elif(else if的缩写):如果前面的if条件不满足,判断本条件
elif ma20 < ma60:
# 记录第一个判断依据:均线空头
reason.append('均线空头')
# 子条件:价格跌破20日均线
if price < ma20:
# 记录第二个判断依据
reason.append('跌破20日均线')
# 三重条件判断:
# 条件A:成交量 > 平均成交量的1.2倍(放量确认)
# 条件B:RSI > 30(未超卖,避免在恐慌中卖出)
if volume > avg_volume * 1.2 and rsi > 30:
# 同时满足三个条件,发出卖出信号
signal = 'SELL' # 修改信号为卖出
reason.append('放量下跌') # 记录第三个判断依据
# ==================== 第六步:震荡市场判断(else分支) ====================
# 条件3:均线纠缠(MA20 ≈ MA60)
# else:如果前面的if和elif条件都不满足,执行本分支
else:
# 市场处于震荡期,趋势不明朗,建议观望
reason.append('均线纠缠,观望')
# ==================== 第七步:返回结果 ====================
# 将原因列表用分号连接成字符串
# '; '.join(reason)将['a', 'b', 'c']转换为'a; b; c'
return signal, '; '.join(reason)
# ==================== 测试案例:不同市场情景 ====================
# 创建测试数据列表(元组形式)
# 每个元组包含6个参数:(price, ma20, ma60, volume, avg_volume, rsi)
signals = [
# 案例1:满足买入条件(均线多头+突破+放量+RSI未超买)
(18.5, 18.0, 17.5, 2500000, 2000000, 45), # 预期:BUY
# 案例2:均线多头但量能不足(不满足放量条件)
(18.5, 18.0, 17.5, 1500000, 2000000, 65), # 预期:HOLD
# 案例3:均线多头+突破+放量但RSI超买(风险较高)
(18.5, 18.0, 17.5, 2500000, 2000000, 75), # 预期:HOLD
# 案例4:满足卖出条件(均线空头+跌破+放量)
(16.5, 18.0, 17.5, 2500000, 2000000, 25), # 预期:SELL
]
# 打印表头
print('交易信号分析:')
# 打印分隔线(80个等号)
print('-' * 80)
# ==================== 遍历每个测试案例 ====================
# for循环:依次处理每个市场情景
# 元组解包:将每个元组的6个值分别赋给对应的变量
for price, ma20, ma60, volume, avg_vol, rsi in signals:
# 调用generate_signal函数生成交易信号
signal, reason = generate_signal(price, ma20, ma60, volume, avg_vol, rsi)
# 格式化输出:显示市场数据和对应的交易信号
# {price:.1f}:保留1位小数
print(f'价格={price:.1f}, MA20={ma20:.1f}, MA60={ma60:.1f}, 信号={signal}, 原因=[{reason}]')39.3 循环结构
39.3.1 for循环
理论背景:迭代的数学定义
迭代(Iteration)是指重复执行某个过程,每次迭代都使结果更接近目标。
收敛性(Convergence): \[ \lim_{n \to \infty} |x_{n+1} - x_n| = 0 \]
金融应用: - 数值方法: 牛顿法求根、梯度下降 - 迭代优化: 投资组合优化 - 模拟仿真: 蒙特卡洛模拟
# =============================================================================
# 题目:演示for循环在金融计算中的应用
# =============================================================================
# for循环是Python中最常用的迭代结构,用于遍历序列中的元素
# 本任务包含两个案例:复利计算和波动率计算
# 金融应用:投资回报计算、风险度量、时间序列分析
import numpy as np # 导入NumPy库,用于数值计算
# ==================== 案例1:复利终值计算 ====================
# 复利是金融学的核心概念:利息产生利息
# 公式:FV = PV × (1 + r)^n
# 其中FV是终值,PV是现值,r是利率,n是期数
# 定义初始参数
principal = 10000 # 本金:初始投资金额(元)
rate = 0.05 # 年利率:5%(0.05表示5%)
years = 10 # 投资年限:10年
# 打印表头
print('复利增长过程:')
# 打印分隔线(50个减号)
print('-' * 50)
# 打印列标题:使用格式化字符串对齐列
# {<6}:左对齐,宽度6个字符
print(f'{"年份":<6}{"年初本金":<12}{"利息":<12}{"年末余额":<12}')
# 打印分隔线
print('-' * 50)
# ==================== for循环:逐期计算复利 ====================
# 初始化当前余额为本金
amount = principal # amount表示每年的累计金额
# range(1, years + 1):生成从1到years的整数序列
# range(start, stop)生成从start到stop-1的整数(左闭右开区间)
# range(1, 11)生成[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for year in range(1, years + 1):
# 计算当年利息:年初本金 × 利率
interest = amount * rate # 利息随余额增长而增长(复利的核心)
# 计算年末余额:年初本金 + 当年利息
# amount += interest 等价于 amount = amount + interest
amount += interest # 余额累积
# 格式化输出:显示每年的增长过程
# {amount - interest}:年初本金(年末余额 - 当年利息)
# {interest}:当年利息
# {amount}:年末余额
print(f'{year:<6}{amount - interest:<12.2f}{interest:<12.2f}{amount:<12.2f}')
# ==================== 复利与单利对比分析 ====================
# 打印最终结果
print(f'\n复利终值: {amount:.2f}元')
# amount经过10年复利增长后的最终金额
# 计算单利终值作为对比
# 单利公式:FV = PV × (1 + r × n)
simple_interest = principal * (1 + rate * years)
print(f'单利对比: {simple_interest:.2f}元')
# 单利只对本金计算利息,不计算利息的利息
# 计算复利优势(复利 - 单利)
compound_advantage = amount - simple_interest
print(f'复利优势: {compound_advantage:.2f}元')
# 复利优势体现了"利息产生利息"的威力
# ==================== 案例2:年化波动率计算 ====================
# 波动率是金融风险的核心度量指标
# 年化波动率 = 日收益率标准差 × √252
# 其中252是一年的交易日数量
# 定义日收益率序列(10个交易日)
daily_returns = [0.02, -0.01, 0.03, -0.02, 0.01, 0.04, -0.03, 0.02, -0.01, 0.01]
# 打印原始数据
print(f'\n日收益率: {daily_returns}')
# 使用NumPy计算并显示统计摘要
print(f'日收益率均值: {np.mean(daily_returns):.4f}')
# np.mean():计算数组的平均值
print(f'日收益率标准差: {np.std(daily_returns):.4f}')
# np.std():计算数组的标准差(衡量波动程度)
# ==================== 手动计算标准差(深入理解) ====================
# 标准差公式:σ = √(Σ(xi - μ)² / (n-1))
# 其中μ是均值,n是样本数量
# 第一步:计算样本数量
n = len(daily_returns) # len()返回列表长度
# 第二步:计算平均收益率
mean_return = sum(daily_returns) / n
# sum():列表求和;除以n得到平均值
# 第三步:计算方差(使用列表推导式)
# 列表推导式:[(r - mean_return) ** 2 for r in daily_returns]
# 语法:[表达式 for 变量 in 序列]
# 作用:对序列中每个元素应用表达式,生成新列表
variance = sum([(r - mean_return) ** 2 for r in daily_returns]) / (n - 1)
# 计算过程:
# 1. (r - mean_return):每个收益率与均值的偏差
# 2. (r - mean_return) ** 2:偏差的平方(消除负号)
# 3. sum(...):所有平方偏差之和
# 4. 除以(n-1):样本方差(使用n-1是无偏估计)
# 第四步:计算标准差(方差的平方根)
volatility_daily = np.sqrt(variance)
# np.sqrt():计算平方根
# 第五步:年化波动率
# 日波动率 × √252(252是一年交易日数)
volatility_annual = volatility_daily * np.sqrt(252)
# 年化波动率:将日波动率转换为年化水平
# ==================== 对比NumPy和手动计算 ====================
print(f'\n手动计算年化波动率: {volatility_annual:.4f}')
# 显示手动计算结果
print(f'NumPy计算年化波动率: {np.std(daily_returns) * np.sqrt(252):.4f}')
# 使用NumPy内置函数计算,验证结果一致性代码深度解析:
range()函数:range(stop): 0到stop-1range(start, stop): start到stop-1range(start, stop, step): 自定义步长
列表推导式:
[(r - mean_return) ** 2 for r in daily_returns]- 简洁的循环创建列表
- 比显式循环快5-10倍
- Pythonic的惯用法
复利公式: \[ FV = PV \times (1 + r)^n \]
- FV: 终值(Future Value)
- PV: 现值(Present Value)
- r: 利率
- n: 期数
39.3.2 while循环
理论背景:不动点迭代
while循环常用于不动点迭代(Fixed Point Iteration):
\[ x_{n+1} = g(x_n) \]
收敛条件: - 压缩映射: \(|g'(x)| < 1\) 对所有 \(x\) - 利普希茨条件: \(|g(x) - g(y)| \leq L |x - y|\), \(L < 1\)
金融应用: - 期权定价: 二叉树模型 - 方程求解: 牛顿法求隐含波动率 - 优化算法: 梯度下降迭代
# =============================================================================
# 题目:使用while循环实现牛顿迭代法求平方根
# =============================================================================
# 牛顿法(Newton's Method)是一种强大的数值算法,用于求解方程的根
# 本任务演示while循环在迭代算法中的应用
# 金融应用:期权定价中的隐含波动率求解、债券收益率计算
import numpy as np # 导入NumPy库
# ==================== 定义牛顿法求平方根函数 ====================
def sqrt_newton(x, tolerance=1e-6, max_iter=100):
"""
使用牛顿迭代法计算平方根
数学原理:
求解方程 f(x) = x² - S = 0
牛顿迭代公式:x_{n+1} = x_n - f(x_n) / f'(x_n)
简化为:x_{n+1} = 0.5 * (x_n + S / x_n)
参数:
x (float): 初始猜测值(迭代起点)
tolerance (float): 容差,控制精度(默认1e-6,即0.000001)
max_iter (int): 最大迭代次数,防止无限循环(默认100次)
返回:
float: 平方根的近似值
"""
# 定义要求根的数
S = 2.0 # 目标:求√2的值
# 初始化:设置当前近似值为初始猜测
x_old = x # x_old表示第n次迭代的值
# ==================== 打印迭代过程表头 ====================
print(f'牛顿法求√{S}:')
# 打印表头:显示列名
print(f'{"迭代":<6}{"近似值":<15}{"误差":<15}')
# 打印分隔线(40个减号)
print('-' * 40)
# ==================== for循环:迭代求解 ====================
# 注意:虽然用for循环,但内部有break语句
# 实际应用中也可以用while循环:while error >= tolerance
for i in range(max_iter):
# ==================== 牛顿迭代公式 ====================
# x_{n+1} = 0.5 × (x_n + S / x_n)
# 直观理解:当前猜测和S/当前猜测的平均值
x_new = 0.5 * (x_old + S / x_old)
# 计算新的近似值
# ==================== 计算误差 ====================
# 绝对误差:|x_{n+1} - x_n|
error = abs(x_new - x_old)
# abs():绝对值函数
# ==================== 打印当前迭代结果 ====================
# {i+1}:迭代次数(从1开始计数)
# {x_new:<15.10f}:近似值,宽度15,保留10位小数
# {error:<15.10f}:误差,宽度15,保留10位小数
print(f'{i+1:<6}{x_new:<15.10f}{error:<15.10f}')
# ==================== 检查收敛条件 ====================
# 如果误差小于容差,认为已收敛,停止迭代
if error < tolerance:
# 收敛成功:显示收敛信息
print(f'\n收敛! 迭代{i+1}次后达到精度要求')
# break语句:立即退出循环
break # 跳出for循环
# ==================== 更新迭代值 ====================
# 为下一次迭代做准备
x_old = x_new
# 将新值赋给旧值,继续下一次迭代
# ==================== for-else结构 ====================
# else子句:只有当for循环正常结束(未执行break)时才执行
else:
# 未收敛:达到最大迭代次数仍未达到精度要求
print(f'\n警告: 未在{max_iter}次内收敛')
# 可能原因:初始猜测值不佳、函数不收敛
# ==================== 返回最终结果 ====================
return x_new # 返回平方根的近似值
# ==================== 调用牛顿法函数 ====================
# 从初始猜测值1.0开始迭代
sqrt_approx = sqrt_newton(1.0)
# 参数说明:1.0是初始猜测值,其他参数使用默认值
# 使用NumPy内置函数计算精确值(用于对比)
sqrt_actual = np.sqrt(2)
# np.sqrt():NumPy的平方根函数,使用高度优化的算法
# ==================== 结果对比与误差分析 ====================
print(f'\n近似值: {sqrt_approx:.10f}')
# 显示牛顿法计算的结果(10位小数)
print(f'实际值: {sqrt_actual:.10f}')
# 显示NumPy计算的结果(精确值)
# 计算并显示绝对误差
absolute_error = abs(sqrt_approx - sqrt_actual)
print(f'误差: {absolute_error:.2e}')
# {:.2e}:科学计数法,保留2位小数
# 例如:1.23e-06表示0.00000123
# ==================== 金融应用:隐含波动率计算 ====================
def implied_volatility(option_price, S, K, T, r=0.05, max_iter=100):
"""
使用牛顿法求期权隐含波动率
背景知识:
Black-Scholes期权定价公式:
C = S × N(d1) - K × e^(-rT) × N(d2)
隐含波动率问题:
已知市场期权价格,反推波动率参数σ
这是无法用解析法求解的,必须使用数值方法
牛顿迭代公式:
σ_{n+1} = σ_n - (BS(σ_n) - MarketPrice) / Vega(σ_n)
参数:
option_price (float): 市场期权价格
S (float): 标的资产当前价格
K (float): 期权行权价
T (float): 到期时间(年)
r (float): 无风险利率,默认5%
max_iter (int): 最大迭代次数
返回:
float: 隐含波动率的估计值
"""
# ==================== 初始化波动率猜测 ====================
sigma = 0.3 # 初始波动率猜测:30%(常见的股票波动率水平)
# 定义收敛容差
tolerance = 1e-6 # 精度要求:0.0001%
# ==================== 牛顿迭代循环 ====================
for i in range(max_iter):
# 注意:这里是简化版演示
# 实际应用需要实现完整的Black-Scholes公式和Vega计算
# 完整版本应该包含:
# price_bs = black_scholes(S, K, T, r, sigma) # BS公式计算期权价格
# vega = vega_greek(S, K, T, r, sigma) # Vega:期权价格对波动率的导数
# sigma_new = sigma - (price_bs - option_price) / vega # 牛顿迭代公式
# ==================== 简化版本(仅演示逻辑) ====================
# 假设:期权价格与波动率成正比(线性近似)
# 实际中这是非线性的,这里仅为演示
price_diff = option_price - (S * 0.6) # 价格差异
sigma_new = sigma + price_diff * 0.1 # 调整波动率
# ==================== 检查收敛 ====================
# 如果波动率变化小于容差,认为已收敛
if abs(sigma_new - sigma) < tolerance:
break # 退出循环
# ==================== 更新波动率 ====================
sigma = sigma_new # 为下一次迭代做准备
# ==================== 返回结果 ====================
return sigma # 返回隐含波动率
# ==================== 隐含波动率计算演示 ====================
print(f'\n隐含波动率计算:')
print(f'期权价格: 5.0元, 标的价格: 100元')
# 调用函数计算隐含波动率
# 参数:期权价格5.0元,标的价格100元,行权价105元,到期时间1年
iv = implied_volatility(5.0, 100, 105, 1)
# 显示结果
print(f'隐含波动率: {iv:.2%}')
# {:.2%}:百分比格式,保留2位小数
# 例如:0.2523显示为25.23%代码深度解析:
- 牛顿法原理: \[ x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)} \]
- 使用函数值和导数
- 二阶收敛速度(每次迭代有效位数翻倍)
- 适合光滑函数求根
- 收敛判断:
abs(x_new - x_old) < tolerance: 绝对误差- 或相对误差:
abs(x_new - x_old) / abs(x_old) < tolerance - 避免无限循环
- 金融应用:隐含波动率:
- 反问题: 从期权价格反推波动率
- 无法用解析解,必须数值求解
- 牛顿法是标准方法
39.3.3 循环控制语句
补充说明:break和continue
break: 立即退出循环continue: 跳过本次迭代,继续下一次
# =============================================================================
# 题目:演示循环控制语句break和continue的用法
# =============================================================================
# break和continue是控制循环执行流程的重要语句
# 金融应用:数据筛选、异常值处理、交易信号触发
# ==================== break语句演示 ====================
# break:立即退出循环,不再执行剩余的迭代
print('break演示(找到第一个正收益):')
# 定义收益率序列(包含正负收益)
returns = [-0.02, 0.03, -0.01, 0.04, 0.01, -0.03, 0.02]
# 场景:寻找第一个正收益的交易日
# enumerate()函数:同时获取索引和值
# enumerate(returns)生成:(0, -0.02), (1, 0.03), (2, -0.01), ...
for i, ret in enumerate(returns):
# 判断:当前收益率是否为正
if ret > 0:
# 找到第一个正收益
print(f' 第{i+1}天: {ret:.2%}')
# break语句:立即退出for循环
break # 不再检查后续元素
# 注意:循环在第2天(索引1)就停止了
# 后续的天数(3-7天)都不会被访问
# ==================== continue语句演示 ====================
# continue:跳过本次迭代的剩余代码,继续下一次迭代
print('\ncontinue演示(跳过负收益):')
# 初始化计数器
positive_count = 0 # 用于统计正收益天数
# 遍历所有收益率
for ret in returns:
# 判断:当前收益率是否为负
if ret < 0:
# 负收益:跳过本次迭代
continue # 直接进入下一次循环,不执行后面的代码
# 只有执行到这里的才是正收益(因为负收益被continue跳过了)
positive_count += 1 # 计数器加1
print(f' 正收益: {ret:.2%}')
# 显示正收益的值
# 显示统计结果
print(f'\n正收益天数: {positive_count}天')
# 输出:正收益的天数(不包含负收益)
# ==================== 嵌套循环与for-else结构 ====================
# 嵌套循环:循环内部还有循环
# for-else:else子句在循环正常结束时执行(未被break中断)
print('\n嵌套循环演示:')
# 外层循环:i从0到2
for i in range(3):
# 内层循环:j从0到2
for j in range(3):
# 判断:是否在对角线上(i等于j)
if i == j:
# 对角线元素:显示
print(f' ({i}, {j}): 对角线元素')
else:
# 非对角线元素:跳过
continue # 跳过本次内层循环
# ==================== for-else结构 ====================
# 内层for循环的else子句
# 只有当内层循环正常完成(未被break中断)时才执行
else:
print(f'第{i}行完成')
# 这表示内层循环检查完了所有j值
# 输出解读:
# 第0行:(0,0)显示,(0,1)和(0,2)跳过,然后显示"第0行完成"
# 第1行:(1,1)显示,(1,0)和(1,2)跳过,然后显示"第1行完成"
# 第2行:(2,2)显示,(2,0)和(2,1)跳过,然后显示"第2行完成"39.4 函数高级应用
39.4.1 可变参数与关键字参数
**理论背景:*args和kwargs的原理
Python支持可变参数,这是通过元组(tuple)和字典(dict)实现的:
*args: 收集所有位置参数为元组**kwargs: 收集所有关键字参数为字典
函数签名示例:
def func(a, b, *args, **kwargs):
pass调用示例:
func(1, 2, 3, 4, x=5, y=6)
# a=1, b=2
# args=(3, 4)
# kwargs={'x': 5, 'y': 6}# =============================================================================
# 题目:实现现金流现值计算函数(使用可变参数)
# =============================================================================
# 现值(Present Value)是金融学的核心概念
# 公式:PV = Σ(CF_t / (1+r)^t),其中CF_t是第t期现金流,r是贴现率
# 本任务演示*args可变参数的使用
# 金融应用:投资决策、债券定价、项目评估
# ==================== 定义现值计算函数 ====================
def PV(R, *NCF, verbose=False):
"""
计算现金流现值(Present Value)
数学原理:
PV = CF₁/(1+r)¹ + CF₂/(1+r)² + ... + CFₙ/(1+r)ⁿ
其中CF_t是第t期现金流,r是贴现率
参数:
R (float): 贴现率(如0.05表示5%)
*NCF (float): 可变数量的现金流(Net Cash Flow)
可以是任意数量的现金流
verbose (bool): 是否显示详细计算过程(默认False)
返回:
float: 所有现金流的现值总和
"""
# ==================== 初始化变量 ====================
pv = 0 # 现值累加器,初始值为0
n = 1 # 期数计数器,从第1期开始
# ==================== 条件输出:是否显示详细过程 ====================
# 如果verbose为True,显示计算过程表头
print('现值计算过程:') if verbose else None
# 三元表达式:条件为真时执行print,否则什么都不做(None)
print('-' * 60) if verbose else None
# 打印分隔线(60个减号)
# ==================== for循环:遍历每期现金流 ====================
# *NCF收集所有传入的现金流参数,形成元组
for cf in NCF:
# 计算折现因子(Discount Factor)
# 公式:DF = 1 / (1+r)^n
discount_factor = 1 / (1 + R) ** n
# 折现因子表示未来1元在当前的价值
# 计算当前现金流的现值
# PV = CF × DF
discounted_cf = cf * discount_factor
# 将未来现金流折现到当前
# 累加现值
pv += discounted_cf
# pv = pv + discounted_cf的简写形式
# ==================== 条件输出:显示每期计算 ====================
if verbose:
# 格式化输出:显示期数、现金流、折现因子、现值
print(f' 第{n}期: 现金流={cf:8.2f}, 折现因子={discount_factor:.6f}, 现值={discounted_cf:8.2f}')
# {cf:8.2f}:宽度8,保留2位小数
# {discount_factor:.6f}:保留6位小数
# 期数递增
n += 1 # 为下一期做准备
# ==================== 条件输出:显示汇总结果 ====================
if verbose:
# 打印分隔线
print('-' * 60)
# 显示现值总和
print(f'现值总和: {pv:.2f}元')
# ==================== 返回最终结果 ====================
return pv # 返回现值总和
# ==================== 案例1:简单投资项目 ====================
print('案例1: 投资项目现金流')
# 定义现金流序列
cash_flows = [-10000, 8000, 12000]
# 解读:
# -10000:初始投资(第0年,负数表示流出)
# 8000:第1年回报(正数表示流入)
# 12000:第2年回报(正数表示流入)
# 调用PV函数计算净现值(NPV)
# *cash_flows:解包操作,将列表元素作为独立参数传递
# 等价于:PV(0.05, -10000, 8000, 12000)
pv1 = PV(0.05, *cash_flows)
# 显示结果
print(f'NPV(净现值): {pv1:.2f}元\n')
# NPV > 0:项目创造价值,值得投资
# NPV < 0:项目破坏价值,不应投资
# ==================== 案例2:多期项目(详细输出) ====================
print('案例2: 多期项目')
# 定义5年期项目的现金流
project_flows = [
-50000, # 第0年:初始投资
10000, # 第1年:回报
15000, # 第2年:回报
20000, # 第3年:回报
25000, # 第4年:回报
30000 # 第5年:回报
]
# 调用PV函数,设置verbose=True显示详细计算过程
pv2 = PV(0.08, *project_flows, verbose=True)
# 参数说明:
# 0.08:贴现率8%
# *project_flows:解包现金流列表
# verbose=True:显示详细计算过程
# ==================== 案例3:债券定价 ====================
print('\n案例3: 债券定价')
# 定义债券现金流
# 场景:10年期债券,面值1000元,票面利率5%(每年50元利息)
bond_flows = [50] * 9 + [1050]
# 解读:
# [50] * 9:前9年每年50元利息
# [1050]:第10年50元利息 + 1000元本金
# 调用PV函数计算债券现值(债券价格)
pv_bond = PV(0.06, *bond_flows)
# 参数说明:
# 0.06:市场收益率6%(贴现率)
# *bond_flows:解包债券现金流列表
# 显示债券定价结果
print(f'债券现值: {pv_bond:.2f}元\n')
# 如果现值 > 面值(1000):债券溢价(市场利率 < 票面利率)
# 如果现值 < 面值(1000):债券折价(市场利率 > 票面利率)代码深度解析:
折现公式: \[ PV = \sum_{t=1}^{n} \frac{CF_t}{(1+r)^t} \]
- \(CF_t\): 第t期现金流
- \(r\): 贴现率
- \(t\): 时间期
净现值(NPV):
- NPV > 0: 项目创造价值
- NPV < 0: 项目破坏价值
- NPV = 0: 盈亏平衡
不定参数的好处:
- 函数通用性强
- 可以处理任意数量的现金流
- 金融应用:处理不同期限的债券
39.4.2 递归函数
理论背景:递归与数学归纳法
递归(Recursion)是函数调用自身的技术。
递归三要素: 1. 基准情形(Base Case): 递归终止条件 2. 递归关系(Recursive Relation): 问题如何分解 3. 收敛性: 确保递归最终会终止
数学归纳法: - 归纳基础: 验证n=1成立 - 归纳假设: 假设n=k成立 - 归纳步骤: 证明n=k+1也成立
# =============================================================================
# 题目:演示递归函数在金融计算中的应用
# =============================================================================
# 递归(Recursion)是函数调用自身的技术
# 本任务包含三个案例:阶乘、二叉树期权定价、斐波那契数列
# 金融应用:期权定价、路径依赖期权、组合管理
import numpy as np # 导入NumPy库,用于数值计算
# ==================== 案例1:递归计算阶乘 ====================
def factorial(n):
"""
计算n的阶乘:n! = 1×2×3×...×n
递归定义:
- 基准情形:0! = 1, 1! = 1
- 递归关系:n! = n × (n-1)!
参数:
n (int): 非负整数
返回:
int: n的阶乘值
"""
# ==================== 基准情形(Base Case)====================
# 递归终止条件:防止无限递归
if n <= 1:
# 0! = 1, 1! = 1(数学定义)
return 1
# ==================== 递归情形(Recursive Case)====================
# 递归调用:函数调用自身
# n! = n × (n-1)!
return n * factorial(n - 1)
# 执行过程(以factorial(3)为例):
# 3! = 3 × 2!
# = 3 × (2 × 1!)
# = 3 × (2 × (1 × 0!))
# = 3 × (2 × (1 × 1))
# = 3 × 2 × 1 × 1
# = 6
# ==================== 测试阶乘函数 ====================
print('阶乘计算:')
# 定义测试数据:不同整数的阶乘
test_values = [1, 5, 10, 20]
# for循环:依次计算每个数的阶乘
for n in test_values:
result = factorial(n) # 调用递归函数
print(f'{n}! = {result}')
# 输出阶乘结果
# 注意:20!已经是一个非常大的数(19位数字)
# ==================== 案例2:二叉树期权定价模型 ====================
def binomial_tree(S, K, T, r, sigma, n, call=True):
"""
二叉树模型计算期权价格(Cox-Ross-Rubinstein模型)
原理:
将时间离散化为n期,每期股价上涨u倍或下跌d倍
使用风险中性定价理论计算期权现值
参数:
S (float): 标的资产当前价格
K (float): 期权行权价
T (float): 到期时间(年)
r (float): 无风险利率(如0.05表示5%)
sigma (float): 波动率
n (int): 二叉树步数(更多步数=更精确)
call (bool): True=看涨期权, False=看跌期权
返回:
float: 期权价格
"""
# ==================== 第一步:计算模型参数 ====================
# 时间步长:将总时间T分为n等份
dt = T / n
# dt:每期的时间长度
# 上涨因子:u = e^(σ√dt)
u = np.exp(sigma * np.sqrt(dt))
# 股价上涨的倍数
# 下跌因子:d = 1/u
d = 1 / u
# 股价下跌的倍数(保证树的重构特性)
# 风险中性概率:p = (e^(r×dt) - d) / (u - d)
p = (np.exp(r * dt) - d) / (u - d)
# 股价上涨的概率(在风险中性世界中)
# ==================== 第二步:迭代法(动态规划)计算期权价值 ====================
# 注:纯递归在n较大时计算量为O(2^n),会导致计算时间爆炸
# 采用从终端节点向前回推的迭代法,复杂度仅为O(n^2)
# 初始化终端节点(到期日)的期权价值数组
option_values = np.zeros(n + 1) # n+1个终端节点
for j in range(n + 1): # 遍历每个终端节点
# 计算终端股价:S × u^j × d^(n-j)
S_T = S * (u ** j) * (d ** (n - j)) # j次上涨,(n-j)次下跌
if call: # 看涨期权
option_values[j] = max(S_T - K, 0) # 内在价值 = max(S_T - K, 0)
else: # 看跌期权
option_values[j] = max(K - S_T, 0) # 内在价值 = max(K - S_T, 0)
# 从终端节点向根节点回推
for i in range(n - 1, -1, -1): # 从第n-1期回推到第0期
for j in range(i + 1): # 每期有i+1个节点
# 风险中性定价公式:V = e^(-r×dt) × [p×V_up + (1-p)×V_down]
option_values[j] = np.exp(-r * dt) * (
p * option_values[j + 1] + (1 - p) * option_values[j]
) # 折现后的期望价值
# 根节点即为期权当前价格
option_price = option_values[0] # 第0期第0个节点的值
# 返回期权价格
return option_price
# ==================== 测试二叉树模型 ====================
# 定义期权参数
S = 100 # 标的资产价格:100元
K = 105 # 行权价:105元
T = 1 # 到期时间:1年
r = 0.05 # 无风险利率:5%
sigma = 0.2 # 波动率:20%
# 注:生产环境中可使用n=100或更高步数以提升精度
n = 20 # 二叉树步数:20步(教学演示用,减少计算时间)
# 调用二叉树函数计算看涨期权价格
option_price = binomial_tree(S, K, T, r, sigma, n)
print(f'\n二叉树模型计算的期权价格: {option_price:.2f}元')
# 输出:期权的公平价值
# ==================== 案例3:斐波那契数列(递归演示) ====================
def fibonacci(n):
"""
计算斐波那契数列的第n项
递归定义:
- F(0) = 0
- F(1) = 1
- F(n) = F(n-1) + F(n-2)
应用:斐波那契数列在金融技术分析中用于预测支撑阻力位
参数:
n (int): 非负整数
返回:
int: 斐波那契数列的第n项
"""
# ==================== 基准情形 ====================
if n <= 1:
# F(0) = 0, F(1) = 1
return n
# ==================== 递归情形 ====================
# F(n) = F(n-1) + F(n-2)
return fibonacci(n - 1) + fibonacci(n - 2)
# ==================== 测试斐波那契函数 ====================
print(f'\n斐波那契数列前10项:')
# 使用列表推导式生成前10项
fib_sequence = [fibonacci(i) for i in range(10)]
# [fibonacci(0), fibonacci(1), ..., fibonacci(9)]
# 结果:[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# 显示斐波那契数列
print(fib_sequence)代码深度解析:
- 二叉树模型原理:
- 将时间离散化为n期
- 每期价格上涨u倍或下跌d倍
- 风险中性定价: 期望收益率=无风险利率
- CRR模型参数:
- \(u = e^{\sigma \sqrt{\Delta t}}\)
- \(d = 1/u\)
- \(p = \frac{e^{r\Delta t} - d}{u - d}\)
- 递归的效率问题:
- 朴素递归: \(O(2^n)\) (指数级)
- 动态规划: \(O(n^2)\) (平方级)
- 金融应用中必须优化
39.4.3 函数作用域
理论背景:LEGB规则
Python变量查找遵循LEGB作用域层次: 1. L(Local): 局部作用域(函数内) 2. E(Enclosing): 闭包作用域(嵌套函数) 3. G(Global): 模块作用域(文件内) 4. B(Built-in): 内置作用域(Python内置)
# =============================================================================
# 题目:演示Python变量作用域与LEGB规则
# =============================================================================
# 变量作用域决定了变量在程序中的可见范围
# Python使用LEGB规则查找变量:Local -> Enclosing -> Global -> Built-in
# 金融应用:避免全局变量污染、函数封装、参数传递
# ==================== 定义全局变量 ====================
# 全局变量(Global Scope):在模块级别定义的变量
x = 10 # 全局变量x,值为10
y = 20 # 全局变量y,值为20
# ==================== 演示1:局部变量遮蔽全局变量 ====================
def func_local():
"""
演示局部变量如何遮蔽全局变量
作用域规则:
- 函数内定义的变量是局部变量
- 局部变量与全局变量同名时,局部变量优先(遮蔽全局变量)
"""
# 在函数内定义同名变量x
x = 5 # 这是局部变量,不是全局变量x
# 此时有两个x变量:
# - 全局变量x(值为10),在函数外
# - 局部变量x(值为5),在函数内
# 访问的是局部变量x(遮蔽效应)
print(f'函数内x: {x} (局部)')
# ==================== 演示2:使用global修改全局变量 ====================
def func_global():
"""
演示如何使用global关键字修改全局变量
global关键字:
- 声明要修改的是全局变量,而不是创建局部变量
- 不使用global,赋值会创建局部变量
"""
# 声明使用全局变量y
global y # 告诉Python:这里的y是全局变量y
# 修改全局变量y
y = 50 # 现在修改的是全局变量y,不是创建局部变量
# 访问全局变量y
print(f'函数内y: {y} (修改后的全局)')
# ==================== 演示3:闭包作用域(Enclosing)====================
def func_enclosing():
"""
演示嵌套函数中的变量作用域
闭包(Closure):
- 内层函数可以访问外层函数的变量
- 即使外层函数执行完毕,变量仍被保留
"""
# 外层函数的局部变量
z = 100 # 这是func_enclosing的局部变量
# 定义内层函数
def inner():
"""
内层函数:访问外层函数的变量
"""
# 访问x:全局变量
# 访问z:外层函数的变量(Enclosing作用域)
return x + z
# 调用内层函数
return inner() # 返回内层函数的执行结果
# ==================== 执行函数并观察变量变化 ====================
# 显示初始状态
print('初始状态:')
print(f'全局x: {x}, 全局y: {y}')
# 输出:全局x=10, 全局y=20
# 调用func_local(演示局部变量遮蔽)
func_local()
# 函数内打印:函数内x: 5 (局部)
print(f'func_local()后, 全局x: {x} (未改变)')
# 全局变量x仍然是10,没有被修改
# 因为func_local中的x是局部变量,不影响全局变量
# 调用func_global(演示修改全局变量)
func_global()
# 函数内打印:函数内y: 50 (修改后的全局)
print(f'func_global()后, 全局y: {y} (已修改)')
# 全局变量y已经被修改为50
# 因为func_global使用了global关键字
# 调用func_enclosing(演示闭包)
closure_result = func_enclosing()
print(f'闭包结果: {closure_result}')
# 输出:闭包结果: 110(全局x=10 + 外层z=100)
# ==================== 演示4:忘记使用global的错误 ====================
def modify_global_wrong():
"""
错误示例:试图修改全局变量但忘记使用global
常见错误:
- 在函数内直接赋值全局变量
- 没有使用global关键字
- 结果是创建了局部变量,而不是修改全局变量
"""
# 注意:这里没有"global y"声明
# global y # 如果没有这行,会创建局部变量
y = 30 # 这会创建局部变量y,而不是修改全局y
# 此时有两个y变量:
# - 全局变量y(值为50)
# - 局部变量y(值为30),只在函数内有效
# ==================== 验证错误示例 ====================
print(f'\n错误示例测试:')
print(f'修改前全局y: {y}')
# 输出:全局y = 50
modify_global_wrong()
# 函数执行:创建了局部变量y=30
print(f'modify_global_wrong()后, 全局y: {y} (未修改,因为没有global)')
# 输出:全局y = 50(未被修改)
# 因为modify_global_wrong中的y是局部变量代码深度解析:
global关键字:- 声明要修改全局变量
- 不声明则创建局部变量
- 不推荐使用全局变量(代码维护困难)
- 闭包(Closure):
- 内层函数引用外层函数的变量
- 即使外层函数返回,变量仍被保留
- 金融应用:回调函数、策略参数
- 作用域最佳实践:
- 尽量使用局部变量
- 通过参数传递数据
- 避免
global和nonlocal(除非必要)
39.5 lambda表达式
理论背景:匿名函数与函数式编程
lambda表达式源自λ演算(Lambda Calculus),由Alonzo Church在1930年代发明。
语法: lambda parameters: expression
特点: - 匿名: 不需要函数名 - 简洁: 单行表达式 - 函数式: 可作为参数传递
金融应用: - 量化策略的快速定义 - 数据清洗的转换函数 - 回调函数
# =============================================================================
# 题目:演示lambda表达式在金融计算中的应用
# =============================================================================
# lambda(匿名函数)是简洁的单行函数定义方式
# 语法:lambda parameters: expression
# 金融应用:快速定义计算逻辑、高阶函数参数、回调函数
# ==================== 案例1:简单数学函数 ====================
# lambda语法:lambda 参数列表: 表达式
# 特点:单个表达式,自动返回结果,无需return语句
# 定义平方函数(lambda版本)
square = lambda x: x**2
# 解读:
# - lambda x:定义参数x
# - x**2:计算x的平方(返回值)
# - square:将lambda函数赋值给变量square
# 定义立方函数(lambda版本)
cube = lambda x: x**3
# 计算x的三次方
# ==================== 测试简单函数 ====================
print('lambda函数演示:')
# 调用square函数
print(f'平方: {square(5)} = {square(5)}')
# 输出:平方: 25(5²)
# 调用cube函数
print(f'立方: {cube(5)} = {cube(5)}')
# 输出:立方: 125(5³)
# ==================== 案例2:金融收益率计算 ====================
# 定义简单收益率函数
simple_return = lambda initial, final: (final - initial) / initial
# 参数:
# - initial:初始价格
# - final:最终价格
# 公式:(最终价格 - 初始价格) / 初始价格
# 定义复利收益函数
compound_return = lambda initial, rate, periods: initial * (1 + rate) ** periods - initial
# 参数:
# - initial:初始本金
# - rate:每期收益率
# - periods:期数
# 公式:初始本金 × (1+收益率)^期数 - 初始本金
# ==================== 测试收益率函数 ====================
print(f'\n简单收益率: {simple_return(100, 110):.2%}')
# 场景:价格从100涨到110
# 输出:10.00%((110-100)/100 = 0.10)
print(f'复利收益: {compound_return(10000, 0.05, 10):.2f}')
# 场景:10000元,5%年利率,10年复利
# 输出:6288.95元(复利增长)
# ==================== 案例3:多参数lambda - 投资组合净值 ====================
# 定义投资组合净值计算函数
net_value = lambda prices, shares: sum(p * s for p, s in zip(prices, shares))
# 参数:
# - prices:股票价格列表
# - shares:持股数量列表
# 逻辑:
# - zip(prices, shares):将价格和数量配对
# - p * s for p, s in ...:计算每只股票的市值
# - sum(...):求和得到总净值
# 定义测试数据
prices = [10.5, 22.3, 15.8] # 三只股票的价格
shares = [100, 200, 150] # 对应的持股数量
# 计算投资组合净值
value = net_value(prices, shares)
print(f'\n投资组合净值: {value:.2f}元')
# 计算:
# - 股票1:10.5 × 100 = 1050元
# - 股票2:22.3 × 200 = 4460元
# - 股票3:15.8 × 150 = 2370元
# - 总净值:1050 + 4460 + 2370 = 7880元
# ==================== 案例4:lambda与高阶函数 - map ====================
# 高阶函数:接收函数作为参数的函数
# 定义股票列表
stocks = ['贵州茅台', '五粮液', '招商银行']
prices = [1850, 220, 45]
# 使用map()应用lambda函数
# map(function, iterable):对可迭代对象的每个元素应用函数
formatted = list(map(lambda x: f'{x}元', prices))
# lambda x: f'{x}元':将数字格式化为"数字+元"的字符串
# list(...):将map对象转换为列表
print(f'\n格式化价格: {formatted}')
# 输出:['1850元', '220元', '45元']
# ==================== 案例5:lambda与高阶函数 - filter ====================
# filter(function, iterable):过滤符合条件的元素
# 使用filter筛选高价股票
expensive_stocks = list(filter(lambda p: p[1] > 200, zip(stocks, prices)))
# lambda p: p[1] > 200:筛选条件(价格>200)
# zip(stocks, prices):将股票名和价格配对
# p[1]:取元组的第二个元素(价格)
print(f'高价股票: {[s + "=" + str(p) + "元" for s, p in expensive_stocks]}')
# 输出:['贵州茅台=1850元', '五粮液=220元']
# ==================== 案例6:lambda与高阶函数 - sorted ====================
# sorted(iterable, key=function):使用自定义函数排序
# 定义投资组合(字典列表)
portfolio = [
{'name': '贵州茅台', 'return': 0.15},
{'name': '五粮液', 'return': 0.08},
{'name': '招商银行', 'return': 0.12}
]
# 按收益率降序排列
sorted_portfolio = sorted(portfolio, key=lambda x: x['return'], reverse=True)
# lambda x: x['return']:提取收益率作为排序依据
# reverse=True:降序排列(从高到低)
print(f'\n按收益率排序:')
for stock in sorted_portfolio:
print(f" {stock['name']}: {stock['return']:.2%}")
# 输出:
# 贵州茅台: 15.00%
# 招商银行: 12.00%
# 五粮液: 8.00%
# ==================== 案例7:lambda与条件表达式 ====================
# lambda函数可以使用条件表达式(三元表达式)
# 定义交易信号生成函数
get_signal = lambda r: 'BUY' if r > 0.05 else ('SELL' if r < -0.02 else 'HOLD')
# 逻辑:
# - r > 0.05:收益率>5%,买入
# - r < -0.02:收益率<-2%,卖出
# - 其他:观望
# 嵌套三元表达式:
# 'BUY' if condition1 else ('SELL' if condition2 else 'HOLD')
# 定义测试收益率序列
returns = [0.06, -0.03, 0.02, -0.01, 0.08]
# 使用列表推导式生成交易信号
signals = [get_signal(r) for r in returns]
# 显示交易信号
print(f'\n交易信号:')
for r, s in zip(returns, signals):
print(f' 收益率={r:6.2%}: 信号={s}')
# 输出:
# 收益率= 6.00%: 信号=BUY(>5%)
# 收益率=-3.00%: 信号=SELL(<-2%)
# 收益率= 2.00%: 信号=HOLD(在-2%到5%之间)
# 收益率=-1.00%: 信号=HOLD
# 收益率= 8.00%: 信号=BUY代码深度解析:
lambda语法:
lambda args: expression # 只能是单个表达式,不能是语句块 # 自动返回表达式的值何时使用lambda:
- 适合: 简单单行函数
- 适合: 作为参数传递给高阶函数
- 不适合: 复杂逻辑(用def定义)
高阶函数:
map(func, iterable): 对每个元素应用函数filter(func, iterable): 过滤元素sorted(iterable, key=func): 自定义排序
平台任务1解答代码
以下代码与教学平台任务要求完全一致:
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#题目一
salary = 8000 # 基本工资
if salary <= 5000: # 判断基本工资是否小于等于5000
rate = 0 # 基本工资小于等于5000,不扣税,即扣税率为0%
else: # 不满足以上条件时
rate = 0.05 # 基本工资大于5000,扣税率为0.05,即5%
# 计算税后工资,基本工资-扣税,扣税额为超过3000部分的乘以扣税率
salary = salary - (salary - 5000) * rate
print("税后工资为:%d" % salary) # 将税后工资打印输出平台任务2解答代码
以下代码与教学平台任务要求完全一致:
# 注:该代码块包含input()交互输入,渲染时无法执行
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#题目二
sum_salary = 0
salary_list = [] # 定义列表salary_list
salary = 0 # 初始化薪资变量为0
while True: # 条件循环
salary = input('请输入员工的薪资,输入Q结束计算:') # 获取用户键盘输入
if salary.upper() == 'Q': # 条件判断:salary.upper() == 'Q'
print('程序结束') # 输出程序结束
break # 跳出循环
elif int(salary) <= 0: # 否则判断:int(salary) <= 0
print('您输入的数值有误,请重新输入') # 输出您输入的数值有误,请重新输入
continue # 跳过本次迭代
salary_list.append(salary) # 将有效薪资数据添加到列表
sum_salary += int(salary) # 更新sum_salary的值
print(len(salary_list)) # 输出数据长度
print(sum_salary) # 输出薪资数据平台任务3解答代码
以下代码与教学平台任务要求完全一致:
# 注:该代码块包含缩进错误的填空代码,需要在平台上完成
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#题目三
Ri=[0.15,0.20,-0.10,0.35] #收益率序列
Ai=[0.3,0.2,0.3,0.2] #权重序列
TR=0 # 初始化投资组合期望报酬率为0
for j in range(len(Ri)): # 遍历range(len(Ri))中的每个j
TRij=Ri[j]*Ai[j] # 计算第j项资产的加权收益贡献(收益率×权重)
TR+=TRij # 更新TR的值
print("投资组合的期望报酬率为:{:.2f}".format(TR)) # 输出投资组合的期望报酬率为:{:.2f}